#include "Widget.h"

#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QDebug>
#include <QTimer>
#include <QMessageBox>
#include <QGridLayout>

#include <QBluetoothLocalDevice>
#include <QBluetoothDeviceDiscoveryAgent>
#include <QLowEnergyService>
#include <QLowEnergyDescriptor>

Widget::Widget(QWidget *parent) : QWidget(parent)
{
    Init();
}

Widget::~Widget()
{
}

void Widget::SlotSearchButtonClicked()
{
    if(deviceListWidget->count() > 1)
    {
        deviceListWidget->clear();
        auto deviceItem = new QListWidgetItem();
        auto deviceCell = new BluetoothDeviceCell(this);
        deviceItem->setSizeHint(QSize(deviceListWidget->width(), deviceCell->height()));
        deviceCell->SetHeader("名称", "地址", "信号强度");
        deviceListWidget->addItem(deviceItem);
        deviceListWidget->setItemWidget(deviceItem, deviceCell);
    }
    deviceInfoList.clear();
    deviceDiscoveryAgent->start(QBluetoothDeviceDiscoveryAgent::LowEnergyMethod);
    searchButton->setEnabled(false);
    statusLabel->setText("Searching for devices......");
}

void Widget::SlotDeviceDiscovered(const QBluetoothDeviceInfo &info)
{
    if (!(info.coreConfigurations() & QBluetoothDeviceInfo::LowEnergyCoreConfiguration))
    {
        return;
    }
    auto deviceItem = new QListWidgetItem();
    auto deviceCell = new BluetoothDeviceCell();
    deviceItem->setSizeHint(QSize(deviceListWidget->width(), deviceCell->height()));
    deviceCell->SetBluetoothDeviceInfo(info);
    deviceListWidget->addItem(deviceItem);
    deviceListWidget->setItemWidget(deviceItem, deviceCell);

    deviceInfoList.append(info);
}

void Widget::SlotDeviceSearchFinished()
{
    statusLabel->setText("Double click a device to dearch for services");
    searchButton->setEnabled(true);
}

void Widget::SlotDeviceSearchErrorOccurred()
{

}

void Widget::SlotServiceDiscovered(const QBluetoothServiceInfo &info)
{
    if(info.serviceName().isEmpty())
    {
        return;
    }
    QList<QBluetoothUuid> btUuids = info.serviceClassUuids();
    qDebug() << btUuids[0];
    QBluetoothUuid btUuid = btUuids[0];
    auto seriveItem = new QListWidgetItem;
    auto serviceCell = new BluetoothDeviceCell();
    seriveItem->setSizeHint(QSize(serviceListWidget->width(), serviceCell->height()));
    //    serviceCell->SetName(info.serviceName());
    //    serviceCell->SetAddress(btUuid.toString());
    //    serviceCell->SetRssi("");
    serviceListWidget->addItem(seriveItem);
    serviceListWidget->setItemWidget(seriveItem, serviceCell);
    bluetoohUuids.push_back(btUuid);

    qDebug() << "Found new service:" << info.serviceName()
             << '(' << info.device().address().toString() << ')';
    qDebug() << "Found new service uuids:" << info.serviceClassUuids();
}

void Widget::SlotServiceSearchFinished()
{
    statusLabel->setText("Double Click a service to connect to bluetooth");
    QMessageBox::about(this, "Hint", "Service Search Finished!");
}

void Widget::SlotDeviceListWidgetItemActivated(QListWidgetItem *deviceItem)
{
    if (deviceItem == nullptr)
    {
        return;
    }
    if(serviceListWidget->count() > 1)
    {
        serviceListWidget->clear();
        auto item = new QListWidgetItem();
        auto deviceCell = new BluetoothDeviceCell();
        item->setSizeHint(QSize(serviceListWidget->width(), deviceCell->height()));
        deviceCell->SetHeader("名称", "服务Uuid", "null");
        serviceListWidget->addItem(item);
        serviceListWidget->setItemWidget(item, deviceCell);
    }
    bluetoohUuids.clear();

    auto widget = deviceListWidget->itemWidget(deviceItem);
    auto deviceCell = qobject_cast<BluetoothDeviceCell*>(widget);
    auto deviceInfo = deviceCell->GetBluetoothDeviceInfo();

    if (!deviceInfo.isValid())
    {
        return;
    }
    if (lowEnergyController != nullptr && lowEnergyController->state() == QLowEnergyController::ConnectedState)
    {
        lowEnergyController->disconnectFromDevice();
    }
    delete lowEnergyController;
    lowEnergyController = nullptr;

    qDebug() << deviceInfo.name();
    lowEnergyController = QLowEnergyController::createCentral(deviceInfo);
    if(lowEnergyController == NULL)
    {
        QMessageBox::warning(this,"警告","创建控制器失败!");
    }
    //
    connect(lowEnergyController, &QLowEnergyController::connected, this, &Widget::SlotLowEnergyControllerConnected);
    connect(lowEnergyController, &QLowEnergyController::disconnected, this, &Widget::SlotLowEnergyControllerDisconnected);
    connect(lowEnergyController, &QLowEnergyController::serviceDiscovered, this, &Widget::SlotLowEnergyControllerServiceDiscovered);
    connect(lowEnergyController, &QLowEnergyController::discoveryFinished, this, &Widget::SlotLowEnergyControllerDiscoveryFinished);
    connect(lowEnergyController, static_cast<void(QLowEnergyController::*)(QLowEnergyController::Error)>(&QLowEnergyController::error), this, &Widget::SlotLowEnergyControllerError);

    QTimer::singleShot(1000, this, [this](){ lowEnergyController->connectToDevice(); });

    statusLabel->setText("Searching for services......");
}

void Widget::SlotServiceListWidgetItemActivated(QListWidgetItem *serviceItem)
{
    if (serviceItem == nullptr)
    {
        return;
    }
    auto widget = serviceListWidget->itemWidget(serviceItem);
    auto serviceCell = qobject_cast<BluetoothDeviceCell*>(widget);
    auto serviceUuid = serviceCell->GetBluetoothUuid();
    serviceEdit->setText(serviceUuid.toString());
    bool ret = servicesUuids.contains(serviceUuid);
    if(!ret){
        lowEnergyController->disconnectFromDevice();
        return;
    }

    QTimer::singleShot(1000,[=]{ ConnectService(serviceUuid.toString());});

}

void Widget::serviceDiscovered(const QBluetoothServiceInfo & info)
{
    qDebug() << "Found new service:" << info.serviceName()
             << '(' << info.device().address().toString() << ')';
    qDebug() << "Found new service uuids:" << info.serviceClassUuids();
}

void Widget::SlotLowEnergyControllerConnected()
{
    qDebug()<<"Device connect success.";
    QTimer::singleShot(1000, this, [this](){ lowEnergyController->discoverServices(); });
}

void Widget::SlotLowEnergyControllerDisconnected()
{
    qDebug() << "Device disconnected";
}

void Widget::SlotLowEnergyControllerServiceDiscovered(const QBluetoothUuid &newService)
{
    qDebug() << "Device Service Discovered";
}

void Widget::SlotLowEnergyControllerDiscoveryFinished()
{
    qDebug()<<"Services scan finished.";
    servicesUuids = lowEnergyController->services();
    for (auto servicesUuid : servicesUuids)
    {
        qDebug() << servicesUuid.toString();
        QListWidgetItem* item = new QListWidgetItem();
        BluetoothDeviceCell* btDevCell = new BluetoothDeviceCell();
        item->setSizeHint(QSize(serviceListWidget->width(), btDevCell->height()));
        btDevCell->SetBluetoothUuid(servicesUuid);
        serviceListWidget->addItem(item);
        serviceListWidget->setItemWidget(item, btDevCell);
    }
}

void Widget::SlotLowEnergyControllerError(QLowEnergyController::Error error)
{
    qDebug() << "error:" << error;
}

void Widget::ConnectService(QString uuid)
{
    QLowEnergyService *lowEnergyService = nullptr;
    for(int i = 0; i < servicesUuids.length(); i++)
    {
        if(servicesUuids.at(i).toString() == uuid)
        {
            lowEnergyService = lowEnergyController->createServiceObject(servicesUuids.at(i));
            break;
        }
    }
    if (lowEnergyService == nullptr)
    {
        return;
    }
    characters.clear();
    if(characterListWidget->count() > 1)
    {
        characterListWidget->clear();
        auto characterItem = new QListWidgetItem();
        auto characterCell = new BluetoothDeviceCell();
        characterItem->setSizeHint(QSize(characterListWidget->width(), characterCell->height()));
        characterCell->SetHeader("名称", "特征值Uuid", "null");
        characterListWidget->addItem(characterItem);
        characterListWidget->setItemWidget(characterItem, characterCell);
    }

    //打印各种错误信息
    connect(lowEnergyService, static_cast<void(QLowEnergyService::*)(QLowEnergyService::ServiceError)>(&QLowEnergyService::error), this, &Widget::SlotLowEnergyServiceError);
    connect(lowEnergyService, &QLowEnergyService::stateChanged, this, &Widget::SlotLowEnergyServiceStateChanged);
    connect(lowEnergyService, &QLowEnergyService::characteristicChanged, this, &Widget::SlotLowEnergyServiceCharacteristicChanged);
    connect(lowEnergyService, &QLowEnergyService::descriptorWritten, this, &Widget::SlotLowEnergyServiceDescriptorWritten);

    if (lowEnergyService->state() == QLowEnergyService::DiscoveryRequired)
    {
        lowEnergyService->discoverDetails();
    }
    else if (lowEnergyService->state() == QLowEnergyService::ServiceDiscovered)
    {
        const QList<QLowEnergyCharacteristic> chars = lowEnergyService->characteristics();
        for (const QLowEnergyCharacteristic &ch : chars) {
            if (ch.isValid())
            {
                QListWidgetItem* characterItem = new QListWidgetItem();
                BluetoothDeviceCell* characterCell = new BluetoothDeviceCell();
                characterItem->setSizeHint(QSize(characterListWidget->width(), characterCell->height()));
                characterCell->SetBluetoothUuid(ch.uuid());
                characterListWidget->addItem(characterItem);
                characterListWidget->setItemWidget(characterItem, characterCell);
                //
                QLowEnergyDescriptor descriptor = ch.descriptor(QBluetoothUuid::DescriptorType::ClientCharacteristicConfiguration);
                if (descriptor.isValid())
                {
                    //lowEnergyService->writeDescriptor(descriptor, QByteArray::fromHex("FEE1"));
                }
            }
            qDebug()<<ch.uuid();
            characters.push_back(ch);
        }
    }
}

void Widget::SlotLowEnergyServiceError(QLowEnergyService::ServiceError newErrorr)
{
    qDebug() << "service error:" << newErrorr;
}

void Widget::SlotLowEnergyServiceStateChanged(QLowEnergyService::ServiceState newState)
{
    auto lowEnergyService = qobject_cast<QLowEnergyService *>(sender());
    if (lowEnergyService == nullptr)
    {
        return;
    }
    qDebug()<<"State : "<< newState;
    if(newState == QLowEnergyService::ServiceDiscovered){
        const QList<QLowEnergyCharacteristic> chars = lowEnergyService->characteristics();
        for (const QLowEnergyCharacteristic &ch : chars) {
            if (ch.isValid())
            {
                QListWidgetItem* characterItem = new QListWidgetItem();
                BluetoothDeviceCell* characterCell = new BluetoothDeviceCell();
                characterItem->setSizeHint(QSize(characterListWidget->width(), characterCell->height()));
                characterCell->SetBluetoothUuid(ch.uuid());
                characterListWidget->addItem(characterItem);
                characterListWidget->setItemWidget(characterItem, characterCell);
                //
                QLowEnergyDescriptor descriptor = ch.descriptor(QBluetoothUuid::DescriptorType::ClientCharacteristicConfiguration);
                if (descriptor.isValid())
                {
                    //lowEnergyService->writeDescriptor(descriptor, QByteArray::fromHex("FEE1"));
                }
            }
            qDebug()<<ch.uuid();
            characters.push_back(ch);
        }
    }
}

void Widget::SlotLowEnergyServiceCharacteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &newValue)
{

}

void Widget::SlotLowEnergyServiceDescriptorWritten(const QLowEnergyDescriptor &descriptor, const QByteArray &newValue)
{

}

void Widget::SlotReadButtonClicked()
{
    auto characterItem = characterListWidget->currentItem();
    if (characterItem == nullptr)
    {
        return;
    }
    auto widget = characterListWidget->itemWidget(characterItem);
    auto serviceCell = qobject_cast<BluetoothDeviceCell*>(widget);
    auto serviceUuid = serviceCell->GetBluetoothUuid();
    readEdit->setText(serviceUuid.toString());
}

void Widget::SlotWriteButtonClicked()
{
    auto characterItem = characterListWidget->currentItem();
    if (characterItem == nullptr)
    {
        return;
    }
    auto widget = characterListWidget->itemWidget(characterItem);
    auto serviceCell = qobject_cast<BluetoothDeviceCell*>(widget);
    auto serviceUuid = serviceCell->GetBluetoothUuid();
    writeEdit->setText(serviceUuid.toString());
}

void Widget::Init()
{
    setFixedSize(1200, 800);
    auto mainLayout = new QVBoxLayout;
    auto searchLayout = new QHBoxLayout;
    searchButton = new QPushButton("search", this);
    searchButton->setFixedSize(80, 30);
    statusLabel = new QLabel(this);
    searchLayout->addWidget(searchButton);
    searchLayout->addWidget(statusLabel);
    auto deviceCharacterLayout = new QHBoxLayout;
    deviceListWidget = new QListWidget(this);
    deviceListWidget->setFixedSize(590, 360);
    characterListWidget = new QListWidget(this);
    characterListWidget->setFixedSize(590, 360);
    deviceCharacterLayout->addWidget(deviceListWidget);
    deviceCharacterLayout->addWidget(characterListWidget);

    auto serviceWidgetLayout = new QHBoxLayout;
    serviceListWidget = new QListWidget(this);
    serviceListWidget->setFixedSize(590, 360);
    auto widget = new QWidget(this);
    widget->setFixedSize(590, 360);
    auto widgetLayout = new QVBoxLayout;
    widgetLayout->setMargin(100);
    auto gridLayout = new QGridLayout;
    serviceEdit = new QLineEdit(this);
    serviceEdit->setFixedSize(320, 30);
    serviceButton = new QPushButton("service", this);
    serviceButton->setFixedSize(50, 30);
    readEdit = new QLineEdit(this);
    readEdit->setFixedSize(320, 30);
    readButton = new QPushButton("read", this);
    readButton->setFixedSize(50, 30);
    writeEdit = new QLineEdit(this);
    writeEdit->setFixedSize(320, 30);
    writeButton = new QPushButton("write", this);
    writeButton->setFixedSize(50, 30);
    gridLayout->addWidget(serviceEdit, 0, 0);
    gridLayout->addWidget(serviceButton, 0, 1);
    gridLayout->addWidget(readEdit, 1, 0);
    gridLayout->addWidget(readButton, 1, 1);
    gridLayout->addWidget(writeEdit, 2, 0);
    gridLayout->addWidget(writeButton, 2, 1);

    auto bottomLayout = new QHBoxLayout;
    bottomLayout->setMargin(0);
    bottomLayout->setSpacing(10);
    cancelButton = new QPushButton("cancel", this);
    cancelButton->setFixedSize(80, 30);
    connectButton = new QPushButton("connect", this);
    connectButton->setFixedSize(80, 30);
    bottomLayout->addStretch();
    bottomLayout->addWidget(cancelButton);
    bottomLayout->addWidget(connectButton);

    widgetLayout->addLayout(gridLayout);
    widgetLayout->addLayout(bottomLayout);
    widget->setLayout(widgetLayout);
    serviceWidgetLayout->addStretch();
    serviceWidgetLayout->addWidget(serviceListWidget);
    serviceWidgetLayout->addWidget(widget);
    serviceWidgetLayout->addStretch();

    mainLayout->addLayout(searchLayout);
    mainLayout->addLayout(deviceCharacterLayout);
    mainLayout->addLayout(serviceWidgetLayout);
    setLayout(mainLayout);

    deviceDiscoveryAgent = new QBluetoothDeviceDiscoveryAgent(this);
    deviceDiscoveryAgent->setLowEnergyDiscoveryTimeout(5000);

    /*-------------------- 初始化设备列表与服务列表 -----------------*/
    //设置设备列表
    auto deviceItem = new QListWidgetItem();
    //创建自定义窗口,放入到listwidget中
    auto deviceCell = new BluetoothDeviceCell(this);
    //设置item的高
    deviceItem->setSizeHint(QSize(deviceListWidget->width(), deviceCell->height()));
    //设置label显示
    deviceCell->SetHeader("名称", "地址", "信号强度");
    //将item加入到listwidget中
    deviceListWidget->addItem(deviceItem);
    //设置item的窗口为自定义的窗口
    deviceListWidget->setItemWidget(deviceItem, deviceCell);

    //设置服务列表的标题
    auto serviceItem = new QListWidgetItem();
    //创建自定义窗口，放入到listwidget中
    auto serviceCell = new BluetoothDeviceCell();
    //设定item的尺寸
    serviceItem->setSizeHint(QSize(serviceListWidget->width(), serviceCell->height()));
    //设置label的显示
    //第一个加进去的item在最上面，相当于标题
    serviceCell->SetHeader("名称", "服务Uuid", "null");
    //将item加入到listwidget中
    serviceListWidget->addItem(serviceItem);
    //设置item的窗口为自定义的窗口
    serviceListWidget->setItemWidget(serviceItem, serviceCell);

    //设置服务列表的标题
    auto characterItem = new QListWidgetItem();
    //创建自定义窗口，放入到listwidget中
    auto characterCell = new BluetoothDeviceCell();
    //设定item的尺寸
    characterItem->setSizeHint(QSize(characterListWidget->width(), characterCell->height()));
    //设置label的显示
    //第一个加进去的item在最上面，相当于标题
    characterCell->SetHeader("名称", " 特征值Uuid", "null");
    //将item加入到listwidget中
    characterListWidget->addItem(characterItem);
    //设置item的窗口为自定义的窗口
    characterListWidget->setItemWidget(characterItem, characterCell);

    /*------------- deviceDiscoveryAgent设备搜索对象的信号槽 -------------*/
    connect(deviceDiscoveryAgent, &QBluetoothDeviceDiscoveryAgent::deviceDiscovered, this, &Widget::SlotDeviceDiscovered);
    connect(deviceDiscoveryAgent, &QBluetoothDeviceDiscoveryAgent::finished, this, &Widget::SlotDeviceSearchFinished);
    void (QBluetoothDeviceDiscoveryAgent:: *deviceSearchErrorOccurred)(QBluetoothDeviceDiscoveryAgent::Error) = &QBluetoothDeviceDiscoveryAgent::error;
    connect(deviceDiscoveryAgent, deviceSearchErrorOccurred, this, &Widget::SlotDeviceSearchErrorOccurred);

    //    /*------------- m_btSocket蓝牙套接字的信号槽 ----------------*/
    //    void (QBluetoothSocket:: *socketErrorOccurred)(QBluetoothSocket::SocketError) = &QBluetoothSocket::error;
    //    connect(socket, socketErrorOccurred, this, &MainWindow::SlotSocketErrorOccurred); //错误处理槽函数
    //    connect(socket, &QBluetoothSocket::connected, this, &MainWindow::SlotSocketConnected);//连接成功

    connect(searchButton, &QPushButton::clicked, this, &Widget::SlotSearchButtonClicked);
    connect(deviceListWidget, &QListWidget::itemActivated, this, &Widget::SlotDeviceListWidgetItemActivated);
    connect(serviceListWidget, &QListWidget::itemActivated, this, &Widget::SlotServiceListWidgetItemActivated);

    connect(readButton, &QPushButton::clicked, this, &Widget::SlotReadButtonClicked);
    connect(writeButton, &QPushButton::clicked, this, &Widget::SlotWriteButtonClicked);
}

